<?php
namespace Plu\Library\Services\Platform\Live;

use Plu\Library\Services\ServiceBase,
    Plu\Library\Models\Tga\Live\Rooms as RoomModel,
    Plu\Library\Models\Platform\Tag\TagMap as TagMapModel,
    Plu\Library\Services\Utility\NumberService,
    Plu\Library\Services\Platform\Game\GamesService,
    Plu\Library\Services\Redis\Room\RoomRedis,
    Plu\Library\Services\Redis\Tag\TagRedis,

    Phalcon\Db\Column;

class LiveService extends ServiceBase {
    const CACHE_TIME = 3;

    /**
     * 排序方式，具体参见Live\Rooms Model定义
     */
    protected $sortby = "top";

    /**
     * 查询指定的游戏
     */
    protected $games = [];

    /**
     * 排除指定的游戏
     */
    protected $exgames = [];

    /**
     * 查询指定的房间域名
     */
    protected $domains = [];

    /**
     * 排除指定的房间域名
     */
    protected $exdomains = [];

    /**
     * 查询指定的房间roomid
     */
    protected $roomIds = [];

    /**
     * 排除指定的房间roomid
     */
    protected $exroomIds = [];

    /**
     * 查询指定的uid房间
     */
    protected $uids = [];

    /**
     * 排除指定的uid房间
     */
    protected $exuids = [];

    /**
     * 只搜索在线房间
     * all online offline
     */
    protected $isBroadcast = 'online';

    /**
     * 查询包含长方形封面的房间
     */
    protected $setRectangleCover = false;

    /**
     * 查询包含正方形封面的房间
     */
    protected $setSquareCover = false;

    /**
     * 搜索加密和非加密房间;
     */
    protected $isLocked = 'all';

    /**
     * 搜索收费和非收费房间;
     */
    protected $isFee = 'all';

    protected $filter = 0;

    /**
     * 数据是否需要格式化输出
     */
    protected $formatted = true;

    /**
     * roomtag 根据房间标签获取数据
     */
    protected $roomTags = [];

    /**
     * 排除指定的房间标签
     */
    protected $exroomTags = [];

    /**
     * 额外参数配置
     */
    protected $params = [];

    /**
     * 房间标签使用严格模式
     */
    protected $strictness = false;

    protected $roomRedis;

    protected $tagRedis;

    public function __construct() {
        $this->roomRedis = new RoomRedis;
        $this->tagRedis  = new TagRedis;
    }

    /**
     * 设定需要的排序
     *
     * 如果使用customize 需要传入排序配置规则
     */
    public function setSortby($sortby) {
        if (!in_array($sortby, RoomModel::STREAM_SORT_KEYS)) {
            $sortby = "top";
        }

        $this->sortby = $sortby;

        return $this;
    }

    /**
     * 设定需要获取指定的游戏id
     */
    public function setGames($ids, $isIncludeChildrens = true) {
        if (!is_array($ids)) {
            $ids = array($ids);
        }
        $games = NumberService::toNumberList($ids);

        if ($isIncludeChildrens) {
            $len = count($games);
            for ($c = 0; $c < $len; $c++) {
                $gameid = $games[$c];
                $game = GamesService::getGameInfoById($gameid);
                if (!empty($game['subgames'])) {
                    $games = array_merge($games, $game['subgames']);
                }
            }

            $games = array_values(array_unique($games));
        }

        //merge
        $this->games = array_values(array_unique(array_merge($this->games, $games)));

        return $this;
    }

    /**
     * 设定需要排除的游戏id
     */
    public function setExgames($ids, $isIncludeChildrens = true) {
        if (!is_array($ids)) {
            $ids = array($ids);
        }
        $games = NumberService::toNumberList($ids);

        if ($isIncludeChildrens) {
            $len = count($games);
            for ($c = 0; $c < $len; $c++) {
                $gameid = $games[$c];
                $game = GamesService::getGameInfoById($gameid);
                if (!empty($game['subgames'])) {
                    $games = array_merge($games, $game['subgames']);
                }
            }

            $games = array_values(array_unique($games));
        }
        
        //merge
        $this->exgames = array_values(array_unique(array_merge($this->exgames, $games)));

        return $this;
    }

    /**
     * domains转换为roomids
     * 设定需要获取指定房间的domain,内部强制转换成roomid
     */
    public function setDomains($domains) {
        if (!is_array($domains)) {
            $domains = array($domains);
        }

        //获取有效的domains
        $this->domains = $domains;
        $roomIds = $this->roomRedis->getRoomIds($domains);

        $roomIds = array_values($roomIds);

        $roomIds = NumberService::toNumberList($roomIds);
        
        $this->setRoomIds($roomIds);

        return $this;
    }

    /**
     * 设定需要排除房间的domain
     */
    public function setExdomains($domains) {
        if (!is_array($domains)) {
            $domains = array($domains);
        }

        //获取有效的domains
        $this->exdomains = $domains;
        $roomIds = $this->roomRedis->getRoomIds($domains);

        $roomIds = array_values($roomIds);

        $roomIds = NumberService::toNumberList($roomIds);

        $this->setExroomIds($roomIds);

        return $this;
    }

    /**
     * 设定需要的房间roomid
     */
    public function setRoomIds($roomIds) {
        if (!is_array($roomIds)) {
            $roomIds = array($roomIds);
        }

        $roomIds = NumberService::toNumberList($roomIds);

        $roomIds = array_values(array_unique(array_merge($roomIds, $this->roomIds)));

        $this->roomIds = $roomIds;

        return $this;
    }

    /***
     * 获取已经设定的roomid
     */
    public function getRoomIds() {
        return $this->roomIds;
    }

    /**
     * 设定需要排除的房间roomid
     */
    public function setExroomIds($roomIds) {
        if (!is_array($roomIds)) {
            $roomIds = array($roomIds);
        }

        $roomIds = NumberService::toNumberList($roomIds);

        $roomIds = array_values(array_unique(array_merge($roomIds, $this->exroomIds)));

        $this->exroomIds = $roomIds;

        return $this;
    }

    /**
     * 设定需要的uid
     */
    public function setUids($uids) {
        if (!is_array($uids)) {
            $uids = array($uids);
        }

        $this->uids = $uids;

        $roomIds = $this->roomRedis->getRoomIdsByUids($uids);
        $roomIds = array_values($roomIds);
        $roomIds = NumberService::toNumberList($roomIds);

        $this->setRoomIds($roomIds);

        return $this;
    }

    public function setExuids($uids) {
        if (!is_array($uids)) {
            $uids = array($uids);
        }

        $this->uids = $uids;

        $roomIds = $this->roomRedis->getRoomIdsByUids($uids);
        $roomIds = array_values($roomIds);
        $roomIds = NumberService::toNumberList($roomIds);

        $this->setExroomIds($roomIds);

        return $this;
    }

    /**
     * 设定获取的数据需要的是否是直播中？
     * all online offline
     */
    public function setBroadcastStatus($isBroadcast = 'online') {
        if ($isBroadcast === true) {
            $this->isBroadcast = 'online';
        } elseif ($isBroadcast === false) {
            $this->isBroadcast = 'offline';
        } elseif (gettype($isBroadcast) == 'string') {
            $this->isBroadcast = $isBroadcast;
        }

        return $this;
    }

    /**
     * 设定是否获取加密房间
     *
     * all lock unlock
     */ 
    public function setLockableStatus($isLocked = 'all') {
        $this->isLocked = $isLocked;

        return $this;
    }

    /**
     * 设定是否获取收费房间
     * all fee unfee
     */
    public function setFeeStatus($isFee = 'all') {
        $this->isFee = $isFee;

        return $this;
    } 


    /**
     * 设定出来的数据是否需要格式化
     */
    public function setFormatted($format = true) {
        $this->formatted = (bool)$format;

        return $this;
    }

    public function setFilter($filter = 0) {
        $filter = intval($filter);

        if ($filter > 0) {
            $this->filter = $filter;
        }

        return $this;
    }

    /**
     * 根据 游戏分类 标签获取直播
     * TODO
     */
    public function setCategoryTags($tags) {
        if (!is_array($tags)) {
            $tags = array($tags);
        }

        $tags = $this->tagRedis->validation($tags, TagMapModel::ITEM_TYPES['CATEGORY']);
        $gameIds = TagMapModel::getItemIdsByItemNames($tags, TagMapModel::ITEM_TYPES['CATEGORY']);

        $this->setGames($gameIds);

        //获取指定的id
        return $this;
    }

    /**
     * 排除这些分类
     * TODO
     */
    public function setExCategoryTags($tags) {
        if (!is_array($tags)) {
            $tags = array($tags);
        }

        $tags = $this->tagRedis->validation($tags, TagMapModel::ITEM_TYPES['CATEGORY']);

        $gameIds = TagMapModel::getItemIdsByItemNames($tags, TagMapModel::ITEM_TYPES['CATEGORY']);

        $this->setExgames($gameIds);

        return $this;
    }

    /**
     * 根据 房间标签获取直播
     */
    public function setRoomTags($tags) {
        if (!is_array($tags)) {
            $tags = array($tags);
        }

        $tags = $this->tagRedis->validation($tags, TagMapModel::ITEM_TYPES['ROOM']);

        $tags = array_values(array_unique(array_merge($tags, $this->roomTags)));

        $this->roomTags = $tags;

        return $this;
    }

    /**
     * 排除设定的tags
     */
    public function setExRoomTags($tags) {
        if (!is_array($tags)) {
            $tags = array($tags);
        }

        $tags = $this->tagRedis->validation($tags, TagMapModel::ITEM_TYPES['ROOM']);

        $tags = array_values(array_unique(array_merge($tags, $this->exroomTags)));

        $this->exroomTags = $tags;

        return $this;
    }

    /**
     * 查询包含长方形封面的房间
     */
    public function setRectangleCover($isRectangle) {
        $this->setRectangleCover = $isRectangle;

        return $this;
    }


    /**
     * 查询包含正方形封面的房间
     */
    public function setSquareCover($isSquare) {
        $this->setSquareCover = $isSquare;

        return $this;
    }

    /**
     * 尽量减少使用
     */
    public function setParams($sql) {
        $this->params[] = $sql;

        return $this;
    }

    /**
     * 设定标签匹配是否是严格模式，如果标签为空数据则不返回
     */
    public function setStrictness($strictness = false) {
        $this->strictness = (bool)$strictness;

        return $this;
    }

    /**
     * 重置搜索条件
     */
    public function reset() {
        $this->sortby                = 'top';
        $this->games                 = [];
        $this->exgames               = [];
        $this->domains               = [];
        $this->exdomains             = [];
        $this->roomIds               = [];
        $this->exroomIds             = [];
        $this->uids                  = [];
        $this->exuids                = [];
        $this->roomTags              = [];
        $this->exroomTags            = [];
        $this->params                = [];
        $this->strictness            = false;
        $this->setRectangleCover = false;
        $this->setSquareCover = false;

        $this->isBroadcast = 'online';
        $this->isLocked    = 'all';
        $this->isFee       = 'all';
        $this->filter      = 0;

        $this->formatted   = true;

        return $this;
    }

    /**
     * 计算guid
     */
    private function getGuid($params = array()) {
        $p = array(
            $this->sortby,
            $this->games,
            $this->exgames,
            $this->domains,
            $this->exdomains,
            $this->roomIds,
            $this->exroomIds,
            $this->uids,
            $this->exuids,
            $this->roomTags,
            $this->exroomTags,
            $this->params,
            $this->isBroadcast,
            $this->setSquareCover,
            $this->setRectangleCover,
            $this->isLocked,
            $this->isFee,
            $this->filter,
            $this->formatted,
            $this->strictness
        );

        $p = array_merge($p, $params);

        return md5(serialize($p));
    }

    /**
     * 根据相关条件获取直播信息数据
     *
     * @param $start_index 
     * @param $max_results
     * @param $games   查询指定的游戏
     * @param $exgames 排除指定的游戏
     * @param $channels 查询指定的房间
     * @param $excludes 排除指定的房间
     * @param $isdomain default true  传入的channels或者excludes是否是domain，false为roomids
     * @param $is_broadcast default true 默认只搜索在线房间
     * @param $filter 过滤数据 1 美女 2 kespa 4 只含有vid的直播
     */
    public function getStreams($start_index = 0, $max_results = 50, $cacheTime = null) {
        if (is_null($cacheTime)) {
            $cacheTime = self::CACHE_TIME;
        }

        $cacheHandler = $this->getCacheHandler();
        $now = time();
        if ($cacheTime > 0) {
            $hash = $this->getGuid(func_get_args());
            $guid = sprintf("tgalives_%s", $hash);
            list($streams, $exptime) = $cacheHandler->get($guid);

            if (is_numeric($exptime) && (($now - $exptime) >= $cacheTime)) {
                $streams = array();//reset
            }
        } else {
            $streams = array();
        }

        if (!empty($streams) && is_array($streams)) {
            return $streams;
        }

        if ($this->strictness && empty($this->roomTags)) {
            return array(0, []);
        }

        $roomModel = new RoomModel;

        $roomModel->reset();

        $roomModel->setBroadcastStatus($this->isBroadcast)
            ->setLockableStatus($this->isLocked)
            ->setFeeStatus($this->isFee);

        if (!empty($this->games)) {
            $roomModel->setGames($this->games);
        }

        if (!empty($this->exgames)) {
            $roomModel->setExgames($this->exgames);
        }

        //TODO
        //向下透传的过程中 可以针对broadcast做 roomIds/exroomIds 过滤，减少向下传入的数量
        //这一部分需要在tgarooms表改造完成后 进行优化
        if (!empty($this->roomIds)) {
            $roomModel->setRoomIds($this->roomIds);
        }

        if (!empty($this->exroomIds)) {
            $roomModel->setExroomIds($this->exroomIds);
        }

        if ($this->filter > 0) {
            $roomModel->setFilter($this->filter);
        }

        if($this->setRectangleCover) {
            $roomModel->setRectangleCover($this->setRectangleCover);
        }

        if($this->setSquareCover) {
            $roomModel->setSquareCover($this->setSquareCover);
        }

        //额外sql语句
        if (!empty($this->params)) {
            $roomModel->setParams($this->params);
        }

        list($totalCount, $items) = $roomModel->getStreams($start_index, $max_results, $this->sortby, $this->roomTags, $this->exroomTags, $this->strictness);

        //append quality
        $roomIds = array_column($items, 'id');
        $streamQuality = $this->roomRedis->getStreamQualityByRoomIds($roomIds);

        $items = array_map(function($room) use ($streamQuality) {
            $room['quality'] = $streamQuality[$room['id']]['cornerName'];
            $room['qualityRate'] = (int)$streamQuality[$room['id']]['templateId'];
            return $room;
        }, $items);

        if ($this->formatted) {
            $items = $this->format($items);
        }
        
        $data = array($totalCount, $items);

        if ($cacheTime > 0) {
            $cacheHandler->save($guid, array($data, $now), $cacheTime);
        }

        return $data;
    }

    /**
     * 格式化数据
     */
    private function format($rooms) {
        $data = [];
        array_walk($rooms, function($room) use(&$data) {
            $data[] = array(
                "preview"  => $room['preview'],
                "preview2"  => $room['preview2'],
                "game"     => array(
                    'Id'   => $room['gameid'],
                    'id'   => $room['gameid'],
                    'Name' => $room['gamename'],
                    'name' => $room['gamename'],
                    'tag'  => $room['gametag']
                ),
                "channel"  => array(
                    "id"                 => $room['id'],
                    "name"               => $room['name'],
                    "avatar"             => $room['avatar'],
                    "grade"              => (int)$room['grade'],
                    "url"                => $room['domain'],
                    "status"             => $room['status'],
                    'broadcast_begin'    => $room['broadcast_begin'],
                    'broadcast_duration' => $room['broadcast_duration'],
                    "videos"             => $room['videos'], //always 0
                    "_type"              => $room['_type'],
                    "_subtype"           => $room['_subtype'],//主播类型
                    "belle"              => $room['belle'],
                    "domain"             => $room['domain'],
                    "flowers"            => $room['flowers'],
                    'followers'          => $room['followers'],
                    'glamours'           => $room['glamours'],
                    'tag'                => $room['tag'],
                    'vid'                => (int)$room['vid'],
                    'weight'             => (int)$room['weight'],
                    'live_source'        => (int)$room['live_source'],
                    'stream_types'       => (int)$room['stream_types'],
                    'lockable'           => (bool)$room['lockable'],
                    'fee'                => (int)$room['fee'],
                    'uid'                => (int)$room['uid'],
                    'quality'            => $room['quality'],
                    'qualityRate'        => (int)$room['qualityRate']
                ),
                "viewers" => (int)$room['views'],
                "rvs"     => ceil($room['rvs'])
            );
        });

        return $data;
    }
}
